package com.cyw.common.exceptions;

import com.cyw.common.constants.BaseStatusCode;
import com.cyw.common.constants.StatusCode;
import com.google.common.collect.Lists;

import java.util.ArrayList;
import java.util.List;

/**
 * 基础异常
 * 系统所有自定义异常类都要继承这个异常
 *
 * @author cyw
 * @date 2018-11-23 11:28
 */
public class BaseException extends RuntimeException {

    private static final String PREFIX = "com.cyw.";

    private static final List<String> FOCUS_STACK_PACKAGE = Lists.newArrayList(PREFIX);

    private static final long serialVersionUID = 6034265990406160608L;

    /**
     * 错误码
     */
    private String errorCode;

    /**
     * 用户友好的提示信息
     */
    private String userTip;

    /**
     * 指定异常信息
     * @param message
     */
    public BaseException(String message) {
        super(message);
        this.errorCode = BaseStatusCode.ERROR_COMMON.getCode();
        this.userTip = message;
    }

    /**
     * 指定状态码
     * @param code
     */
    public BaseException(StatusCode code) {
        super(code.getErrorTip());
        this.errorCode = code.getCode();
        this.userTip = code.getUserTip();
    }

    /**
     * 子类调用这个方法可以添加自己关心的堆栈
     *
     * @param focusPackages
     */
    protected BaseException(String... focusPackages) {
        for (String p : focusPackages) {
            FOCUS_STACK_PACKAGE.add(p);
        }
    }

    /**
     * 重新填充堆栈，移除不关心的堆栈
     *
     * @return
     */
    @Override
    public synchronized Throwable fillInStackTrace() {
        super.fillInStackTrace();

        StackTraceElement[] stackTrace = super.getStackTrace();
        List<StackTraceElement> newStackTrace = new ArrayList<>();
        for (StackTraceElement stackTraceElement : stackTrace) {
            String className = stackTraceElement.getClassName();
            if (ignoreStackTrace(className)) {
                continue;
            }
            newStackTrace.add(stackTraceElement);
        }
        this.setStackTrace(newStackTrace.toArray(new StackTraceElement[]{}));
        return this;
    }

    @Override
    public String getMessage() {
        return super.getMessage();
    }

    public String getErrorCode() {
        return errorCode;
    }

    public String getUserTip() {
        return userTip;
    }

    /**
     * 忽略不关心的包的堆栈
     *
     * @param className
     * @return
     */
    private boolean ignoreStackTrace(String className) {
        for (String p : FOCUS_STACK_PACKAGE) {
            if (className.startsWith(p)) {
                return false;
            }
        }
        return true;
    }
}
